﻿using System;
using System.Collections.Generic;
using System.Text;
using Sinacor.Infra.Service.Common;
using Sinacor.Infra.Common.Exceptions;
using Sinacor.Infra.Service.ExceptionHandling;
using Sinacor.Infra.Service.Validation;

namespace Sinacor.Servico.Bovespa.Ordens.BusinessLogic
{
    /// <summary>
    /// BusinessLogic Class - AjusteMercadoFuturo
    /// </summary>
    public class AjusteMercadoFuturo : BaseBusinessLogic
    {
        #region Constantes de Erro

        private const int ERRO_AJUSTEMERCADOFUTURO_REGISTROANTERIOREXISTENTE = 109024;
        private const int ERRO_AJUSTEMERCADOFUTURO_CODIGONEGOCIONAOCADASTRADO = 109025;
        private const int ERRO_AJUSTEMERCADOFUTURO_FATORCOTACAOCODIGONEGOCIONULO = 109026;
        private const int ERRO_AJUSTEMERCADOFUTURO_ERRONAOTRATADO = 109029;
        private const int ERRO_AJUSTEMERCADOFUTURO_DATAPREGAONULO = 109030;
        private const int ERRO_AJUSTEMERCADOFUTURO_OBJETOREQUESTNULO = 109032;
        private const int ERRO_AJUSTEMERCADOFUTURO_NAOPERTENCEMERCADOFUTURO = 109036;
        private const int ERRO_MOVIMENTO_NAO_ABERTO = 109709;

        #endregion

        #region Métodos Públicos

        /// <summary>
        /// Calcula ajuste de posição de mercado futuro
        /// </summary>
        /// <param name="request">Data do pregão</param>
        public void AjustarPosicao(DateTime request)
        {            
            if (request == null)
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_DATAPREGAONULO);
            else
            {
                this.ValidarMovimento();
                
                ResourceAccess.AjusteMercadoFuturo ajusteMercadoFuturo = new ResourceAccess.AjusteMercadoFuturo();
                BusinessEntity.Resultado resultado = ajusteMercadoFuturo.AjustarPosicao(request);

                if (!resultado.Sucesso)
                {
                    if (resultado.CodigoErro != -1)
                    {
                       this.TratarExcecoes(resultado);
                    }
                    else
                    {
                        throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_ERRONAOTRATADO);
                    }
                }
            }
        }

        /// <summary>
        /// Altera um registro de ajuste de mercado futuro
        /// </summary>
        /// <param name="request">Entidade AjusteMercadoFuturo</param>
        public void AlterarAjusteMercadoFuturo(BusinessEntity.AjusteMercadoFuturo request)
        {
            if (request == null)
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_OBJETOREQUESTNULO);
            else
            {
                this.ValidarMovimento();
                
                ResourceAccess.AjusteMercadoFuturo ajusteMercadoFuturo = new ResourceAccess.AjusteMercadoFuturo();
                ajusteMercadoFuturo.AlterarAjusteMercadoFuturo(request);
            }
        }

        /// <summary>
        /// Consulta registros de ajustes de mercado futuro
        /// </summary>
        /// <param name="request">Filtro contendo o código do negócio(opcional)</param>
        /// <returns>Lista de entidades AjusteMercadoFuturo</returns>
        public List<BusinessEntity.AjusteMercadoFuturo> ConsultarAjustesMercadoFuturo(BusinessEntity.Parameter.FiltroAjusteMercadoFuturo request)
        {
            if (request == null)
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_OBJETOREQUESTNULO);
            else
            {
                SinacorValidation validation = new SinacorValidation();
                validation.Validate<BusinessEntity.Parameter.FiltroAjusteMercadoFuturo>(request);

                if (!string.IsNullOrEmpty(request.CodigoNegociacao))
                {
                    Titulo.BusinessEntity.Titulo tituloRequest = new Titulo.BusinessEntity.Titulo();
                    Titulo.BusinessEntity.Titulo tituloResponse;

                    tituloRequest.Codigo = request.CodigoNegociacao;
                    tituloRequest.DataPregao = request.DataPregao;
                    tituloRequest.DataOrdem = request.DataPregao;

                    Titulo.BusinessLogic.Titulo blTitulo = new Titulo.BusinessLogic.Titulo();
                    tituloResponse = blTitulo.ConsultarTituloCodigo(tituloRequest);

                    if (tituloResponse == null)
                        throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_CODIGONEGOCIONAOCADASTRADO);
                    else if (tituloResponse.TipoMercado != Titulo.BusinessEntity.Enum.TipoMercado.Futuro)
                        throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_NAOPERTENCEMERCADOFUTURO);
                }

                ResourceAccess.AjusteMercadoFuturo ajusteMercadoFuturo = new ResourceAccess.AjusteMercadoFuturo();
                return ajusteMercadoFuturo.ConsultarAjustesMercadoFuturo(request);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="listaInclusao"></param>
        /// <param name="listaAlteracao"></param>
        /// <param name="listaExclusao"></param>
        public void ExecutarTransacoes(List<BusinessEntity.AjusteMercadoFuturo> listaInclusao, List<BusinessEntity.AjusteMercadoFuturo> listaAlteracao, List<BusinessEntity.Parameter.FiltroAjusteMercadoFuturo> listaExclusao)
        {
            foreach (BusinessEntity.AjusteMercadoFuturo item in listaInclusao)
                this.IncluirAjusteMercadoFuturo(item);

            foreach (BusinessEntity.AjusteMercadoFuturo item in listaAlteracao)
                this.AlterarAjusteMercadoFuturo(item);

            foreach (BusinessEntity.Parameter.FiltroAjusteMercadoFuturo item in listaExclusao)
                this.ExcluirAjusteMercadoFuturo(item);
        }

        /// <summary>
        /// Exclui um registro de ajuste de mercado futuro
        /// </summary>
        /// <param name="request">Filtro contendo o código do negócio, data do pregão e o ano do pregão</param>
        public void ExcluirAjusteMercadoFuturo(BusinessEntity.Parameter.FiltroAjusteMercadoFuturo request)
        {
            if (request == null)
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_OBJETOREQUESTNULO);
            else
            {
                this.ValidarMovimento();
                
                ResourceAccess.AjusteMercadoFuturo ajusteMercadoFuturo = new ResourceAccess.AjusteMercadoFuturo();
                ajusteMercadoFuturo.ExcluirAjusteMercadoFuturo(request);
            }
        }

        /// <summary>
        /// Inclui um registro de ajuste de mercado futuro
        /// </summary>
        /// <param name="request">Entidade AjusteMercadoFuturo</param>
        public void IncluirAjusteMercadoFuturo(BusinessEntity.AjusteMercadoFuturo request)
        {
            if (request == null)
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_OBJETOREQUESTNULO);
            else
            {
                this.ValidarMovimento();
                
                //Valida as RuleSets da entidade request
                this.ValidarAjusteMercadoFuturo(request);

                ResourceAccess.AjusteMercadoFuturo ajusteMercadoFuturo = new ResourceAccess.AjusteMercadoFuturo();
                ajusteMercadoFuturo.IncluirAjusteMercadoFuturo(request);
            }
        }

        #endregion

        #region Métodos Privados

        /// <summary>
        /// Valida estado do movimento
        /// </summary>
        private void ValidarMovimento()
        {
            Movimento.BusinessEntity.InformacoesMovimento infoMovimento = null;

            infoMovimento = (new Movimento.BusinessLogic.ControleMovimentoOrdens()).ObterInformacoesMovimento(new Movimento.BusinessEntity.DataMovimento());

            if (infoMovimento.EstadoMovimento != Movimento.BusinessEntity.Enum.TipoMovimento.Aberto)
                throw new BusinessException(ERRO_MOVIMENTO_NAO_ABERTO);
        }

        /// <summary> 
        /// Valida as RuleSets da entidade request
        /// </summary>
        /// <param name="request">Entidade AjusteMercadoFuturo</param>
        private void ValidarAjusteMercadoFuturo(BusinessEntity.AjusteMercadoFuturo request)
        {
            #region Validação dos RuleSets GrupoValidacao1

            SinacorValidation validation = new SinacorValidation();
            validation.Validate<BusinessEntity.AjusteMercadoFuturo>(request, "GrupoValidacao1");
            validation = null;

            #endregion

            #region Consultar se já tem registro anterior para o ajuste que se deseja incluir

            BusinessEntity.Parameter.FiltroAjusteMercadoFuturo filtroAjusteMercadoFuturo = new BusinessEntity.Parameter.FiltroAjusteMercadoFuturo();
            filtroAjusteMercadoFuturo.CodigoNegociacao = request.CodigoNegocio;
            filtroAjusteMercadoFuturo.DataPregao = request.DataPregao;

            List<BusinessEntity.AjusteMercadoFuturo> listaAjusteMercadoFuturo = this.ConsultarAjustesMercadoFuturo(filtroAjusteMercadoFuturo);

            if (listaAjusteMercadoFuturo.Count > 0)
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_REGISTROANTERIOREXISTENTE);

            #endregion

            #region Consultar se o código do negócio está cadastrado

            Sinacor.Servico.Bovespa.Titulo.BusinessLogic.Titulo titulo = new Sinacor.Servico.Bovespa.Titulo.BusinessLogic.Titulo();
            Sinacor.Servico.Bovespa.Titulo.BusinessEntity.Titulo tituloRequest = new Sinacor.Servico.Bovespa.Titulo.BusinessEntity.Titulo();
            Sinacor.Servico.Bovespa.Titulo.BusinessEntity.Titulo tituloResponse;

            tituloRequest.Codigo = request.CodigoNegocio;
            tituloRequest.DataOrdem = request.DataPregao;

            tituloResponse = titulo.ConsultarTituloCodigo(tituloRequest);

            if (tituloResponse == null)
                //Não houve retorno na consulta do código do negócio
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_CODIGONEGOCIONAOCADASTRADO);

            if (!tituloResponse.FatorCotacao.HasValue)
                //Fator de cotação do código do negócio é nulo
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_FATORCOTACAOCODIGONEGOCIONULO);

            if (tituloResponse.TipoMercado != Titulo.BusinessEntity.Enum.TipoMercado.Futuro)
                //Titulo não pertence ao mercado futuro
                throw new BusinessException(ERRO_AJUSTEMERCADOFUTURO_NAOPERTENCEMERCADOFUTURO);

            request.Fator = Convert.ToDecimal(tituloResponse.FatorCotacao);
            request.PrecoExercicio = tituloResponse.PrecoExercicio;

            #endregion

            #region Validação dos RuleSets GrupoValidacao2

            validation = new SinacorValidation();
            validation.Validate<BusinessEntity.AjusteMercadoFuturo>(request, "GrupoValidacao2");
            validation = null;

            #endregion
        }

        /// <summary>
        /// FGualberto.7comm - Task 6417
        /// implemetação Tratamento de Erro
        /// </summary>
        /// <param name="request"></param>
        private void TratarExcecoes(BusinessEntity.Resultado request)
        {
            if ( String.IsNullOrEmpty(request.Argumentos) )
            {
                throw new BusinessException(request.CodigoErro);
            }
            else
            {
                List<object> lista = ErrorMessage.ConvertXmlArgumentsToParameters(request.Argumentos);
                throw new BusinessException(request.CodigoErro, lista.ToArray());
            }
        }

        #endregion
    }
}
